package com.coffee.wakeagent;


import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

class MulticastUtil {

	/**
	 * @param args
	 * @throws Exception
	 */

	// 广播地址
	private static String BROADCAST_IP ;// 广播IP
	private static int BROADCAST_INT_PORT; // 不同的port对应不同的socket发送端和接收端
	
	MulticastSocket broadSocket;// 用于接收广播信息

	InetAddress broadAddress;// 广播地址

	DatagramSocket sender;// 数据流套接字 相当于码头，用于发送信息

	public MulticastUtil() {
		try {
			InputStream in = getClass().getResourceAsStream("/wakeonlan.properties");
			Properties p = new Properties();
			p.load(in);
			BROADCAST_IP=p.getProperty("BROADCAST_IP", "230.0.0.1");
			BROADCAST_INT_PORT=Integer.valueOf(p.getProperty("BROADCAST_INT_PORT", "40005"));
			// 初始化
			broadSocket = new MulticastSocket(BROADCAST_INT_PORT);
			broadAddress = InetAddress.getByName(BROADCAST_IP);
			sender = new DatagramSocket();
			System.out.println("初始化完毕");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("*****lanSend初始化失败*****" + e.toString());
		}
	}

	void join() {
		try {
			broadSocket.joinGroup(broadAddress); // 加入到组播地址，这样就能接收到组播信息
			new Thread(new GetPacket()).start(); // 新建一个线程，用于循环侦听端口信息
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("*****加入组播失败*****");
			e.printStackTrace();
		}

	}

	// 当局域网内的在线机子收到广播信息时响应并向发送广播的ip地址主机发送返还信息，达到交换信息的目的
	void returnHeartBeat() {
		byte[] b = new byte[1024];
		DatagramPacket packet;
		try {
			InetAddress addr = InetAddress.getLocalHost();
			String myip=addr.getHostAddress().toString();
			String hostName = addr.getHostName().toString();
			b = ("heartbeat@" + myip+"@"+getMacAddressString()+"@"+hostName+"@"+System.getProperties().getProperty("os.name")).getBytes();
			packet = new DatagramPacket(b, b.length, /*InetAddress.getByName(ip)*/broadAddress, BROADCAST_INT_PORT);
			sender.send(packet);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("*****发送返还信息失败*****");
		}
	}

	/** 
     * 按照"XX-XX-XX-XX-XX-XX"格式，获取本机MAC地址 
     * @return 激活的所有网卡的MAC
     * @throws Exception 
     */  
    List<String> getMacAddress(){  
    	List<String> macs=new ArrayList<String>();
    	try {
        Enumeration<NetworkInterface> ni = NetworkInterface.getNetworkInterfaces();  
        while(ni.hasMoreElements()){
            NetworkInterface netI = ni.nextElement();  
            byte[] bytes = netI.getHardwareAddress();  
            if(netI.isUp() && netI != null && bytes != null && bytes.length == 6){  
                StringBuffer sb = new StringBuffer();  
                for(byte b:bytes){  
                     //与11110000作按位与运算以便读取当前字节高4位  
                     sb.append(Integer.toHexString((b&240)>>4));  
                     //与00001111作按位与运算以便读取当前字节低4位  
                     sb.append(Integer.toHexString(b&15));  
                 }  
                 macs.add(sb.toString().toUpperCase()); 
            }  
        }  
    	} catch (Exception e) {
    		e.printStackTrace();
		}
        return macs;  
    }  
    /** 
     * 按照"XX-XX-XX-XX-XX-XX"格式，获取本机MAC地址 
     * @return 激活的所有网卡的MAC
     * @throws Exception 
     */  
    String getMacAddressString(){  
    	StringBuffer sbAll = new StringBuffer();  
    	try {
    		Enumeration<NetworkInterface> ni = NetworkInterface.getNetworkInterfaces();  
    		while(ni.hasMoreElements()){
    			NetworkInterface netI = ni.nextElement();  
    			byte[] bytes = netI.getHardwareAddress();  
    			if(netI.isUp() && netI != null && bytes != null && bytes.length == 6){  
    				StringBuffer sb = new StringBuffer();  
    				for(byte b:bytes){  
    					//与11110000作按位与运算以便读取当前字节高4位  
    					sb.append(Integer.toHexString((b&240)>>4));  
    					//与00001111作按位与运算以便读取当前字节低4位  
    					sb.append(Integer.toHexString(b&15));  
    				} 
    				sbAll.append((sb.toString().toUpperCase())); 
    				sbAll.append(";"); 
    			}  
    		}  
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	sbAll.deleteCharAt(sbAll.length()-1);  
    	return sbAll.toString();  
    }  
	class GetPacket implements Runnable { // 新建的线程，用于侦听
		public void run() {
			DatagramPacket inPacket;

			String[] message;
			while (true) {
				try {
					inPacket = new DatagramPacket(new byte[1024], 1024);
					broadSocket.receive(inPacket); // 接收广播信息并将信息封装到inPacket中
					message = new String(inPacket.getData(), 0, inPacket.getLength()).split("@"); // 获取信息，并切割头部，判断是何种信息（find--上线，retn--回答，offl--下线）
					InetAddress addr = InetAddress.getLocalHost();
					String ip=addr.getHostAddress().toString();
//					if (message[1].equals(ip))
//						continue; // 忽略自身
					if (message[0].equals("requestheartbeat")) { // 如果是请求信息
						System.out.println("网关请求心跳包");
						returnHeartBeat();
					} else if (message[0].equals("commond")) { // 如果是返回信息
						System.out.println("网关发送指令:"+message[2]);
						if (ip.equals(message[1])) {
							Runtime runtime=Runtime.getRuntime();
							runtime.exec(message[2]);
						}
					}

				} catch (Exception e) {
					// TODO: handle exception
					System.out.println("线程出错 " + e);
				}
			}
		}
	}
}